package com.beiding.jsonanalyzer.querylink;

import com.beiding.jsonanalyzer.analyze.func.FuncBase;
import com.beiding.jsonanalyzer.analyze.query.ComparatorResult;
import com.beiding.jsonanalyzer.analyze.query.NodeQueryBuilder;
import com.beiding.jsonanalyzer.flow.Branch;
import com.beiding.jsonanalyzer.flow.BranchNode;
import com.beiding.jsonanalyzer.flow.ValueNode;
import com.beiding.jsonanalyzer.visit.VisitAble;
import com.beiding.jsonanalyzer.visit.Visitor;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

public abstract class JoinQueryLinkNode<W extends ValueNode> extends QueryLinkNodeAdapter<W> {

    private Logger logger = Logger.getLogger(JoinQueryLinkNode.class.getName());

    private NodeQueryBuilder onCondition = new NodeQueryBuilder();

    private QueryLinkNode rightNode;


    public JoinQueryLinkNode(QueryLinkNode leftNode, QueryLinkNode rightNode) {
        super(leftNode);
        this.rightNode = rightNode;
    }

    /**
     * 连接条件
     *
     * @param onCondition
     * @return
     */
    public JoinQueryLinkNode<W> on(NodeQueryBuilder onCondition) {
        this.onCondition = onCondition;
        return this;
    }

    protected abstract void doJoin(BranchNode<W> r, BranchNode<W> left, BranchNode<W> right, FuncBase<ComparatorResult> onCondition);


    @Override
    protected VisitAble<BranchNode<W>> doExec(VisitAble<BranchNode<W>> preResult) {

        return visitor -> {
            FuncBase<ComparatorResult> baseQuery = onCondition.createInstance();

            Map<Object, BranchNode<W>> left = new HashMap<>();
            Map<Object, BranchNode<W>> right = new HashMap<>();

            // 改造成性能更高的锁结构
            Object newBranchLock = new Object();

            preResult.visit(new Visitor<BranchNode<W>>() {
                @Override
                public void onNode(BranchNode<W> b) {
                    {
                        //当左侧产生一个分支时
                        synchronized (newBranchLock) {
                            //先放入到左侧
                            left.put(b.getBranch().getRefer(), b);
                            BranchNode<W> rn = right.get(b.getBranch().getRefer());
                            if (rn == null) {
                                return;
                            }

                            //必须在相同的任务槽上执行. 确保线程安全
                            if (b.getBranch().getTaskSlot() != rn.getBranch().getTaskSlot()) {
                                return;
                            }

                            //创建一个新的分支节点

                            Branch<W> branch = b.getBranch();


                            BranchNode<W> queuedBranch = new BranchNode<>(branch);

                            //此处生成一个新的流
                            doJoin(queuedBranch, b, rn, baseQuery);

                            //创建一个新的数据流

                            visitor.onNode(queuedBranch);
                        }

                    }
                }
            });

            VisitAble<BranchNode<W>> bs = rightNode.exec().getBranches();
            bs.visit(new Visitor<BranchNode<W>>() {
                @Override
                public void onNode(BranchNode<W> b) {
                    //当右侧产生一个分支时
                    synchronized (newBranchLock) {
                        right.put(b.getBranch().getRefer(), b);
                        BranchNode<W> ln = left.get(b.getBranch().getRefer());
                        if (ln == null) {
                            return;
                        }

                        if (ln.getBranch().getTaskSlot() != b.getBranch().getTaskSlot()) {
                            return;
                        }

                        BranchNode<W> queuedBranch = new BranchNode<>(b.getBranch());


                        //此处生成一个新的流
                        doJoin(queuedBranch, ln, b, baseQuery);

                        //创建一个新的数据流
                        visitor.onNode(queuedBranch);
                    }
                }
            });
        };
    }
}
